/*****************************************************************************
******************************************************************************

bmpdiff_mult

Author: Gordon McCreight
 email: gordon@mccreight.com

date modified: 2008-05-13
      version: 0.04

  License: GPL 2
Copyright: 2008 by Gordon McCreight

usage: bmpdiff_mult tolerance_r tolerance_g tolerance_b image_a.bmp image_b.bmp image_c.bmp image_d.bmp
tolerances are 0-255

description:
  Compare multiple isometric BMP files and print a list of pixel positions
  where they differ.  Prints a comma seperated list of x,y (for
  one match) or x,y,x,y,x,y for
  multiple matches.  Prints one line per image.

Note: can be compiled like so:
g++ -o bmpdiff_mult bmpdiff_mult.cpp EasyBMP.cpp

After you compile, you might want to test with this:
./bmpdiff_mult 0 0 0 test_images/first.bmp test_images/second.bmp test_images/third.bmp

******************************************************************************
*****************************************************************************/

#include <stdlib.h>
#include "EasyBMP.h"

//#define DEBUG

using namespace std;

//[tag:performance:gem] Not sure if the "static inline" does any good.
static inline double Abs (double Nbr) {
    if( Nbr >= 0 )
        return Nbr;
    else
        return -Nbr;
}

int main( int argc, char* argv[] ) {

    int tolerance = 10;
    int optind = 1;

    int tolerance_r = atoi(argv[ optind ]);
    optind++;

    int tolerance_g = atoi(argv[ optind ]);
    optind++;

    int tolerance_b = atoi(argv[ optind ]);
    optind++;

    int has_tolerance_bool = 0;
    if (tolerance_r > 0 || tolerance_g > 0 || tolerance_b > 0) {
        has_tolerance_bool = 1;
    }

    BMP ImageA;
    BMP ImageB;

#ifdef DEBUG
    fprintf( stderr, "Loading ImageA BMP image '%s'\n", argv[optind] );
#endif

    ImageA.ReadFromFile(argv[ optind ]);
    optind++;

    int first_height = ImageA.TellHeight();
    int first_width = ImageA.TellWidth();

    int img_read_ok = 1;
    int first_time = 1;

    while (1) {

        if (first_time) {
            first_time = 0;
        }
        else {
            RangedPixelToPixelCopy( ImageB, 1 , first_width,
                first_height, 1, ImageA, 1, 1 );

#ifdef DEBUG
              fprintf( stderr, "swapping\n" );
#endif
        }

#ifdef DEBUG
          fprintf( stderr, "Loading ImageB BMP image '%s'\n", argv[optind] );
#endif
        
        img_read_ok = ImageB.ReadFromFile(argv[ optind ]);
        optind++;

        if (img_read_ok == 0) {
            exit(0);
        }

        if( first_width != ImageB.TellWidth()
            || first_height != ImageB.TellHeight() ) {
            fprintf( stderr, "The heights or widths do not match\n" );
            exit(2);
        }

        int has_written_results = 0;

        for (int bmp_y = 0; bmp_y < first_height; ++bmp_y) {
            for (int bmp_x = 0; bmp_x < first_width; ++bmp_x) {

                int all_channels_matched = 1;

                RGBApixel* PixelA = ImageA(bmp_x, bmp_y);
                RGBApixel* PixelB = ImageB(bmp_x, bmp_y);

                if ( has_tolerance_bool == 0 ) {
                    // zero tolerance, so do it faster
                    if ( PixelA->Red != PixelB->Red ) {
                        all_channels_matched = 0;
                    }
                    else if ( PixelA->Green != PixelB->Green ) {
                        all_channels_matched = 0;
                    }
                    else if ( PixelA->Blue != PixelB->Blue ) {
                        all_channels_matched = 0;
                    }
                }
                else {
                    if ( Abs(PixelA->Red - PixelB->Red) > tolerance_r ) {
                        all_channels_matched = 0;
                    }
                    else if ( Abs(PixelA->Green - PixelB->Green)
                              > tolerance_g ) {
                        all_channels_matched = 0;
                    }
                    else if ( Abs(PixelA->Blue - PixelB->Blue)
                              > tolerance_b ) {
                        all_channels_matched = 0;
                    }
                }

                if (! all_channels_matched) {
                    if (has_written_results == 1) {
                        cout << ",";
                    }
                    cout << bmp_x << "," << bmp_y;
                    has_written_results = 1;
                }

            }
        }
        
        cout << endl;

    }
    
    return 0;

}
